package myLog

import (
	"errors"
	"io"
	"log"
	"os"
	"sync"
)

//日志级别
const (
	TraceLevel = iota
	DebugLevel
	InfoLevel
	WarnLevel
	ErrorLevel
)

var mu sync.Mutex

type Log struct {
	//日志级别名称
	Log string
	//日志级别
	level int
	//日志输出前缀
	prefix string
	//是否开启了当前日志级别的输出
	logAble bool
	//标准库
	logger *log.Logger
	//日志输出到哪里
	out io.Writer
}

func (l *Log) log(v ...interface{}) {
	if l.logAble {
		l.logger.Print(v...)
	}
}

func (l *Log) logf(str string, args ...interface{}) {
	if l.logAble {
		l.logger.Printf(str, args...)
	}
}

// 初始化相关log
var (
	traceLog = &Log{Log: "trace", prefix: "\033[30m[trace]\033[0m ", out: os.Stdout, logAble: false, level: 0}
	debugLog = &Log{Log: "debug", prefix: "\033[36m[debug]\033[0m ", out: os.Stdout, logAble: false, level: 1}
	infoLog  = &Log{Log: "info", prefix: "\033[34m[info ]\033[0m ", out: os.Stdout, logAble: true, level: 2}
	warnLog  = &Log{Log: "warn", prefix: "\033[33m[warn ]\033[0m ", out: os.Stdout, logAble: true, level: 3}
	errorLog = &Log{Log: "error", prefix: "\033[31m[error]\033[0m ", out: os.Stdout, logAble: true, level: 4}
)

func init() {
	traceLog.logger = log.New(traceLog.out, traceLog.prefix, log.LstdFlags|log.Lshortfile)
	debugLog.logger = log.New(debugLog.out, debugLog.prefix, log.LstdFlags|log.Lshortfile)
	infoLog.logger = log.New(infoLog.out, infoLog.prefix, log.LstdFlags|log.Lshortfile)
	warnLog.logger = log.New(warnLog.out, warnLog.prefix, log.LstdFlags|log.Lshortfile)
	errorLog.logger = log.New(errorLog.out, errorLog.prefix, log.LstdFlags|log.Lshortfile)
}

var logs = []*Log{traceLog, debugLog, infoLog, warnLog, errorLog}

type HandleLog func(l *Log)

//logsOp 对日志数组中每个日志log进行处理
func logsOp(logHandle HandleLog) {
	for _, log := range logs {
		logHandle(log)
	}
}

//SetLogLevel 设置日志级别
func SetLogLevel(level int) {
	mu.Lock()
	defer mu.Unlock()

	clearLevel()

	if level < 0 {
		for _, log := range logs {
			log.logAble = false
		}
	} else if level >= len(logs) {
		clearLevel()
	} else {
		for i := 0; i < level; i++ {
			logs[i].logAble = false
		}
	}
}

//clearLevel 让所有日志级别都可以输出日志
func clearLevel() {
	logsOp(func(l *Log) {
		l.logAble = true
	})
}

//SetGlobalLogOutPut 设置全局日志输出
func SetGlobalLogOutPut(out io.Writer) {
	logsOp(func(l *Log) {
		l.logger.SetOutput(out)
	})
}

func SetGlobalLogMulOutPut(out ...io.Writer) {
	logsOp(func(l *Log) {
		l.logger.SetOutput(io.MultiWriter(out...))
	})
}

//SetLogOutPut 设置某个级别的日志输出
func SetLogOutPut(logLevel int, out io.Writer) {
	if logLevel < 0 || logLevel >= len(logs) {
		panic(errors.New("logLevel is wrong"))
	}
	logs[logLevel].logger.SetOutput(out)
}

func SetLogMulOutPut(logLevel int, out ...io.Writer) {
	if logLevel < 0 || logLevel >= len(logs) {
		panic(errors.New("logLevel is wrong"))
	}
	logs[logLevel].logger.SetOutput(io.MultiWriter(out...))
}

func Info(v ...interface{}) {
	infoLog.log(v...)
}

func Infof(str string, args ...interface{}) {
	infoLog.logf(str, args...)
}

func Trace(v ...interface{}) {
	traceLog.log(v...)
}

func Tracef(str string, args ...interface{}) {
	traceLog.logf(str, args...)
}

func Debug(v ...interface{}) {
	debugLog.log(v...)
}

func Debugf(str string, args ...interface{}) {
	debugLog.logf(str, args...)
}

func Warn(v ...interface{}) {
	warnLog.log(v...)
}

func Warnf(str string, args ...interface{}) {
	warnLog.logf(str, args...)
}

func Error(v ...interface{}) {
	errorLog.log(v...)
}

func Errorf(str string, args ...interface{}) {
	errorLog.logf(str, args...)
}
